package main.com.yyx.pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;


//TODO 线程确保minCount

public class ComboPooledDataSource implements PooledDataSource {

    // 数据库驱动
    private String jdbcDriver;

    // 数据库访问地址
    private String jdbcURL;

    // 数据库连接用户名
    private String jdbcUsername;

    // 数据库连接密码
    private String jdbcPassword;

    //初始化连接数
    private int initCount;

    // 连接池中最小连接数,会保持然后永远不会移除
    private int minCount;

    // 连接池中最大连接数
    private int maxCount;

    static {

    }

    public ComboPooledDataSource() {
        this.jdbcURL = DBConfigXML.jdbcURL;
        this.jdbcUsername = DBConfigXML.jdbcUsername;
        this.jdbcPassword = DBConfigXML.jdbcPassword;
        this.initCount = DBConfigXML.initCount;
        this.minCount=DBConfigXML.minCount;
        this.maxCount = DBConfigXML.maxCount;

        // 加载数据库驱动程序
        try {
            // 加载MYSQL JDBC驱动程序
            Class.forName(this.jdbcDriver);
            System.out.println("Success loading Mysql Driver!");
        } catch (ClassNotFoundException e) {
            System.out.print("Error loading Mysql Driver!");
            e.printStackTrace();
        }
        // 初始化数据库连接池管道
        createMyPooledConnection(initCount);
    }


    @Override
    public MyPooledConnection getMyPooledConnection() {
        Vector<MyPooledConnection> myPooledConnectionVector =PooledConnectionPoolManager.getMyPooledConnectionVector();
        if(myPooledConnectionVector.size()<1) {
            throw new RuntimeException("连接池初始化参数错误");
        }
        MyPooledConnection myPooledConnection=null;
        try {
            ReentrantLock lock=new  ReentrantLock(true);
            //管道未满则创建，管道满了则采用公平锁轮询等待，确保先来的先拿到空闲连接
            lock.lock();
            try{
                while (myPooledConnection==null){
                    myPooledConnection = getRealConnectionFromPool();
                }
            }finally {
                lock.unlock();
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return myPooledConnection;
    }

    private MyPooledConnection getRealConnectionFromPool() throws SQLException {
        Vector<MyPooledConnection> myPooledConnectionVector =PooledConnectionPoolManager.getMyPooledConnectionVector();
        MyPooledConnection myPooledConnection = null;
        for (MyPooledConnection connection:
             myPooledConnectionVector) {
            if(!connection.isBusy()){
                if(connection.getConnection().isValid(3000)){
                    //状态更新为busy
                    connection.setBusy(true);
                    myPooledConnection=connection;
                } else {
                    Connection con = DriverManager.getConnection(jdbcURL, jdbcUsername, jdbcPassword);
                    connection.setConnection(con);
                    connection.setBusy(true);
                    myPooledConnection = connection;
                }
            }
        }
        if(myPooledConnectionVector.size()<maxCount){
            Connection con = DriverManager.getConnection(jdbcURL, jdbcUsername, jdbcPassword);
            MyPooledConnection connection=new MyPooledConnection(con,true);
            myPooledConnectionVector.add(connection);
        }
        return myPooledConnection;
    }

    /**
     * 数据库连接池在创建管道时，应该去看一下是否达到上限，如果没有，则可以创建。
     *
     * 不仅仅要创建出来，还要标示每一个管道的isBusy标志。
     *
     * @param count
     */
    @Override
    public void createMyPooledConnection(int count) {
        Vector<MyPooledConnection> myPooledConnectionVector =PooledConnectionPoolManager.getMyPooledConnectionVector();
        if(myPooledConnectionVector.size()+count>maxCount) {
            throw new RuntimeException("连接池已满");
        }
        for (int i = 0; i < count; i++) {
            try {
                Connection connection = DriverManager.getConnection(jdbcURL, jdbcUsername, jdbcPassword);
                MyPooledConnection myPooledConnection = new MyPooledConnection(connection, false);
                myPooledConnectionVector.add(myPooledConnection);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }




}
